import sys
import cv2
import glob
import os
import os.path
import numpy as np
import sympy as sp
import mpmath as mp
import math

##打气筒　260度　映射　0-100刻度；　０刻度对应水平线条　相对旋转　-65度，逆时针转65度。
##从左边 到右边 5个指针表盘；　　表盘不是水平安放的， 倾斜 offset角度 的基准表盘。
DIALS = [
  #offset==不是水平的摆放－ －偏移角度。,;    clockwise=False 指针标注数字正好反了；
  [-65-90, True],    ## 45, 表示基准水平线　　往右手边　倾斜了　45度数。
   #上面角度 -65-90 合计是 0刻度的那一条圆心放射线 相对于Y轴（左右两半轴中心线）的旋转角度，逆时针转155度。假定0刻度应该是最顶上那个位点的。
  [0, False],
  [0, True],
  [0, False],
  [0, True]
]


def clear_debug():
    filelist = glob.glob("output/*.jpg")
    for f in filelist:
        os.remove(f)

def write_debug(img, name):
    cv2.imwrite(f"output/{name}.jpg", img)

##查找最佳的 可能线段。
def find_hand_edge(edges):
    ##从最苛刻条件 的开始, 苛刻条件的 检测出的线段 是指针的概率就最大了。
    for threshold in range (80, 20, -2):
        ##参数　阈值！
        lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold = threshold, minLineLength = 30, maxLineGap = 5)
        if lines is not None:
            return lines[0][0]   ##第一条线段，  多条情况　挑选？


# turn the edge of a hand into a ray from the point closest to the centre
def generate_hand_ray(center_point, edge):
    center = sp.Point(center_point)
    first = sp.Point(edge[0:2])
    second = sp.Point(edge[2:4])
    first_dist = center.distance(first)
    second_dist = center.distance(second)

    return sp.Ray(first, second) if first_dist < second_dist else sp.Ray(second, first)



def read_dial(config, idx, img):
    offset, clockwise = config
    offset_r = offset * (np.pi / 180)

    height, width = img.shape[:2]
    ##指针的旋转中心点，就是圆形截图图片中心
    center = [width / 2, height / 2]
    radius = int(width / 2)
    circle = sp.Circle(sp.Point(center), radius)

    offset_ray = sp.Ray(sp.Point(center), angle=mp.radians(offset))
    offset_img = img.copy()
    origin_point = [ center[0], 0 ]
    offset_point = [
      math.cos(offset_r) * (origin_point[0] - center[0]) - math.sin(offset_r) * (origin_point[1] - center[1]) + center[0],
      math.sin(offset_r) * (origin_point[0] - center[0]) + math.cos(offset_r) * (origin_point[1] - center[1]) + center[1]
    ]
    ##画出 0刻度位置的放射线。
    cv2.line(offset_img, (int(center[0]), int(center[1])), (int(offset_point[0]), int(offset_point[1])), (0, 255, 0), 2)
    write_debug(offset_img, f"dial-{idx}")

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    blurred = cv2.GaussianBlur(gray, (5,5), 0)
    write_debug(blurred, f"blurred-{idx}")

    edges = cv2.Canny(blurred, 30, 130)
    #edges = cv2.Canny(blurred, 50, 200)
    write_debug(edges, f"edges-{idx}")

    #[表指针的直线段] 查找最佳的 可能指针线段。
    edge = find_hand_edge(edges)
    ##参数没调好 就找不到；   edges-4.jpg 基本没剩下什么轮廓了。
    if edge is  None:
        return None   ##没找到指针
    hand_edge_img = img.copy()
    cv2.line(hand_edge_img, (edge[0], edge[1]), (edge[2], edge[3]), (0, 255, 0), 2)
    write_debug(hand_edge_img, f"hand-edge-{idx}")

    hand_ray = generate_hand_ray(center, edge)
    circle_intersection = hand_ray.intersection(circle)[0]

    cv2.line(img, (int(center[0]), int(center[1])), (int(circle_intersection.x), int(circle_intersection.y)), (0, 0, 255), 2)
    write_debug(img, f"intersection-{idx}")

    angle_r = math.atan2(circle_intersection.y - center[1], circle_intersection.x - center[0]) - math.atan2(origin_point[1] - center[1], origin_point[0] - center[0])
    angle = angle_r * 180 / np.pi
    #按照　指针线段末端远端点　和圆心点的直线角度，计算刻度数据
    ##表盘不是水平安放的， 倾斜 offset角度 的基准表盘。
    angle =angle-offset

    if angle < 0:
        angle = 360 + angle

    ##映射数字： 360度 　一圈　　 0-10的刻度范围。
    #打气筒　260度　映射　0-100刻度；　
    angle_p = angle/260
    if not clockwise:
        angle_p = 1 - angle_p

    return int(100*angle_p)    ##最大刻度数10



clear_debug()

filename = sys.argv[1] if len(sys.argv) > 1 else ""
filename='test.jpg'
if not os.path.exists(filename):
    print("Usage: python3 power-meter-reader.py <image>")
    exit(1)

original = cv2.imread(filename)
write_debug(original, "original")

originalSize = original.shape[:2]
#图片尺寸归一化
#resizedSize = (int(originalSize[1] * 0.3), int(originalSize[0] * 0.3))
#resized = cv2.resize(original, resizedSize)
#write_debug(resized, "resized")

gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
write_debug(gray, "gray")

blurred = cv2.GaussianBlur(gray, (5,5), 0)
write_debug(blurred, "blurred")
rows_b, cols_b = blurred.shape
#和图片的尺寸　还有很大关系的！！
#HoughCircles(第四个参数minDist太小了 检出圆形太多。
##参数　　早就　按照先前经验　来设置　minDist=20　　 param1=100, param2=43, minRadius=40, maxRadius=70
#circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, 20, np.array([]), param1=100, param2=45, minRadius=int(cols_b*0.38))
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, 40,param1=100, param2=45, minRadius=int(cols_b*0.38))

##正好找到　５个　圆形？？
dials = np.uint16(np.around(circles))[0,:]

sorted_dials = sorted(dials, key=lambda dial: dial[0])
result = ""
##会找到　多个的　圆形盘？　最佳的是　？　适当的且是最大圆盘
for idx, dial in enumerate(sorted_dials):
    x,y,radius = dial
    ##直接截取 圆形的哪一个外包为正方形图片。
    dial_img = original[y-radius:y+radius,x-radius:x+radius].copy()
    value = read_dial(DIALS[0], idx, dial_img)
    if value is not None  and value>=0  and value<=100:
        # draw the outer circle
        cv2.circle(original, (x, y), radius, (0, 255, 0), 2)
        # draw the center of the circle
        cv2.circle(original, (x, y), 2, (0, 0, 255), 3)

        result += str(value)
        break

print("输出的识别刻度数＝",result)

write_debug(original, "circles")
